function shallowCopy(obj) {
    let newObj = {};
    for (let i in obj) {
        if (obj.hasOwnProperty(i)) {
            newObj[i] = obj[i];
        }
    }
    return newObj;
}
// let obj = {
//     name: 'zs',
//     hobby: ['排球', '打篮球', '足球'],
// };
// let newObj = shallowCopy(obj);
// newObj.hobby[0] = '1';
// console.log(newObj);
// console.log(obj);
// 浅拷贝的几种方法
// Object.assign() ...展开运算符 Array.prototype.slice Array.prototype.concat 递归实现

// 深拷贝
// JSON.parse(JSON.stringfy(obj))
// 缺陷 1. undedined,NaN,Infinity 值会被转为null
// 2. 构造函数和原型链缺失
// 3. 函数和Symbol 深拷贝的时候会被忽略
// 4. 如果存在循环引用，会导致深拷贝失败
// 递归 lodash第三方库
function deepCopy(obj) {
    let newObj = obj instanceof Array ? [] : {};
    for (let [k, v] of Object.entries(obj)) {
        newObj[k] = typeof v == 'object' ? deepCopy(v) : v;
    }
    return newObj;
}
// let newObj = deepCopy(obj);
// newObj.hobby[0] = '1';
// console.log(newObj);
// console.log(obj);

// 防抖 触发该事件后，n秒后会执行该事件，n秒内再次触发，会清空计时器，重新开始计时，n秒内不在触发后执行该事件
// 搜索联想功能 调整窗口大小resize 登录邮箱验证
function debounce(fn, delay) {
    let timer;
    return function (...args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, args);
        }, delay);
    };
}
function debounce1(fn, delay, immediate = false) {
    let timer;
    return function (...args) {
        if (timer) clearTimeout(timer);
        if (immediate) {
            let fastRun = !timer;
            timer = setTimeout(() => {
                timer = null;
            }, delay);
            if (fastRun) {
                fn.apply(this, args);
            }
        } else {
            timer = setTimeout(() => {
                fn.apply(this, args);
            }, delay);
        }
    };
}

// 节流 就是一定时间内只能执行一次，n秒内重复触发,只会执行第一次
// 时间戳写法
function throller(fn, delay) {
    let oldTime = new Date();
    return function (...args) {
        let newTime = new Date();
        if (newTime > oldTime > delay) {
            fn.apply(this, delay);
            oldTime = new Date();
        }
    };
}

// 定时器写法
function throller1(fn, delay) {
    let timer = null;
    return function (...args) {
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(this, args);
                timer = null;
            }, delay);
        }
    };
}

// 手写实现call
Function.prototype.myCall = function (context) {
    if (typeof this !== 'function') {
        throw new Error('不是一个函数');
    }
    context = context || window;
    let args = [...arguments].slice(1);
    context.fn = this;
    let result = context.fn(...args);
    delete context.fn;
    return result;
};

let obj = {
    name: 'zs',
};
function getName(...args) {
    console.log(this.name);
    console.log(args);
}

getName.myCall(obj, 2, 4);

Function.prototype.myBind = function (context) {
    if (typeof this !== 'function') {
        throw new Error('不是一个函数');
    }
    let args = [...arguments].slice(1);
    let fn = this;
    context = context || window;
    return function Fn() {
        // new绑定 > 显示绑定
        return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments));
    };
};
let getName1 = getName.myBind(obj, 1);
getName1(2);
